package com.mch.ar.core;

import java.util.Map;
import java.util.Set;

/**
 * 行记录对象。
 * 
 * @since 1.0
 * @author redraiment
 * @mofifier MCHWEB.NET
 */
public final class Record extends AdapterRecord {
	private static final long serialVersionUID = 4925828795902544132L;

	private transient Table table;

	Record(Table table) {
		this();
		this.table = table;
	}

	public Record() {
		put("nullstring", "");
	}

	public Set<String> columnNames() {
		return keySet();
	}

	@Override
	public Object get(Object key) {
		return get((String) key);
	}

	@SuppressWarnings("unchecked")
	public <E> E get(String name) {
		name = DB.parseKeyParameter(name);
		Object value = null;

		if (containsKey(name)) {
			value = super.get(name);
		} else if (table != null && table.relations.containsKey(name)) {
			Association relation = table.relations.get(name);
			Table active = table.dbo.active(relation.target, table.getPkFieldName());
			active.join(relation.assoc(table.name, getInt("id")));
			if (relation.isAncestor() && !relation.isCross()) {
				active.constrain(relation.key, getInt("id"));
			}
			value = (relation.isOnlyOneResult() ? active.first() : active);
		}

		String key = "get_".concat(name);
		if (table != null && table.hooks.containsKey(key)) {
			value = table.hooks.get(key).call(this, value);
		}
		return (E) value;
	}

	/* For primitive types */

	public boolean getBool(String name) {
		return get(name);
	}

	public byte getByte(String name) {
		return get(name);
	}

	public char getChar(String name) {
		return get(name);
	}

	public short getShort(String name) {
		return get(name);
	}

	public Integer getInt(String name) {
		Object o = get(name);
		if (o == null) {
			return null;
		} else if (o instanceof Integer) {
			return (Integer) o;
		} else if (o.getClass().isPrimitive()) {
			return (int) o;
		} else {
			return Integer.parseInt(o.toString());
		}
	}

	public Long getLong(String name) {
		Object o = get(name);
		if (o == null) {
			return null;
		} else if (o instanceof Long) {
			return (Long) o;
		} else if (o.getClass().isPrimitive()) {
			return (Long) o;
		} else {
			return Long.parseLong(o.toString());
		}
	}

	public Float getFloat(String name) {
		Object o = get(name);
		if (o == null) {
			return null;
		} else if (o instanceof Float) {
			return (Float) o;
		} else if (o.getClass().isPrimitive()) {
			return (Float) o;
		} else {
			return Float.parseFloat(o.toString());
		}
	}

	public Double getDouble(String name) {
		Object o = get(name);
		if (o == null) {
			return null;
		} else if (o instanceof Double) {
			return (Double) o;
		} else if (o.getClass().isPrimitive()) {
			return (Double) o;
		} else {
			return Double.parseDouble(o.toString());
		}
	}

	/* For any other types */

	public String getStr(String name) {
		return get(name);
	}

	public <E> E get(String name, Class<E> type) {
		return type.cast(get(name));
	}

	public Record set(String name, Object value) {
		put(name, value);
		return this;
	}

	@Override
	public Object put(String name, Object value) {
		name = DB.parseKeyParameter(name);
		String key = "set_".concat(name);
		if (table != null && table.hooks.containsKey(key)) {// 增加判断 table 不为空
			value = table.hooks.get(key).call(this, value);
		}
		return super.put(name, value);
	}

	/**
	 * 判断对象中是否存在id，如果存在则进行 update；不存在，则进行 insert；
	 */
	public Record save() {
		Object id = get(getTable().getPkFieldName());
		if (id == null || id.toString().trim().equals("")) {
			Record thi = table.create(this);
			if (thi == null) {
				throw new RuntimeException("无新增成功数据，请检查！");
			}
		} else {
			int count = table.update(this);
			if (count == 0) {
				throw new RuntimeException("无更新成功数据，请检查！");
			}
		}
		return this;
	}

	/**
	 * 直接进行 insert；
	 */
	public Record insert() {
		Record thi = table.create(this);
		if (thi == null) {
			throw new RuntimeException("无新增成功数据，请检查！");
		}
		return this;
	}

	/**
	 * 直接进行 update；
	 */
	public Record update() {
		int count = table.update(this);
		if (count == 0) {
			throw new RuntimeException("无更新成功数据，请检查！");
		}
		return this;
	}

	public int destroy() {
		return table.delete(this);
	}

	@Override
	public String toString() {
		StringBuilder line = new StringBuilder();
		for (Map.Entry<String, Object> e : entrySet()) {
			line.append(String.format("%s = %s\n", e.getKey(), e.getValue()));
		}
		return line.toString();
	}

	public Table getTable() {
		return table;
	}
}
